import logging
from typing import Union

from fastapi import HTTPException, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import ValidationError
from redis import RedisError

from app.enums.result_code import ResultCode
from app.exceptions.base import AppException
from app.exceptions.user import (
    InvalidRefreshTokenException,
    InvalidTokenException,
    UserAccountFrozenException,
    UserDuplicateException,
    UserNotFoundException,
)
from app.schemas.base import Response
from app.utils.ip_utils import get_client_ip

logger = logging.getLogger(__name__)


async def http_exception_handler(request: Request, exc: HTTPException):
    """
    HTTP异常处理器

    Args:
        request: 请求对象
        exc: HTTP异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"HTTP {exc.status_code}: {exc.detail}",
        exc_info=True,
        extra={"request": request},
    )

    # 特殊处理413状态码（请求体过大）
    if exc.status_code == status.HTTP_413_REQUEST_ENTITY_TOO_LARGE:
        content = Response(
            code=ResultCode.UPLOAD_FILE_TOO_LARGE.code, msg=ResultCode.UPLOAD_FILE_TOO_LARGE.label, data=None
        ).model_dump()
        return JSONResponse(status_code=exc.status_code, content=content)

    content = Response(code=str(exc.status_code), msg=exc.detail, data=None).model_dump()
    return JSONResponse(status_code=exc.status_code, content=content)


async def app_exception_handler(request: Request, exc: AppException):
    """
    应用异常处理器

    Args:
        request: 请求对象
        exc: 应用异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | "
        f"AppException - Code: {exc.code}, Message: {exc.msg}",
        exc_info=True,
        extra={"request": request},
    )

    # 根据不同的应用异常返回不同的状态码
    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
    if isinstance(
        exc, (UserNotFoundException, UserAccountFrozenException, InvalidTokenException, InvalidRefreshTokenException)
    ):
        status_code = status.HTTP_401_UNAUTHORIZED
    elif isinstance(exc, UserDuplicateException):
        status_code = status.HTTP_409_CONFLICT

    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status_code, content=content)


async def global_exception_handler(request: Request, exc: Exception):
    """
    全局异常处理器

    Args:
        request: 请求对象
        exc: 异常对象

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"Unhandled exception: {str(exc)}",
        exc_info=True,
        extra={"request": request},
    )
    content = Response(
        code=ResultCode.SYSTEM_ERROR.code, msg=str(exc) or ResultCode.SYSTEM_ERROR.label, data=None
    ).model_dump()
    return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=content)


async def type_error_handler(request: Request, exc: TypeError):
    """
    类型错误异常处理器

    Args:
        request: 请求对象
        exc: 类型错误异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"TypeError: {str(exc)}",
        exc_info=True,
        extra={"request": request},
    )
    content = Response(
        code=ResultCode.TYPE_ERROR.code, msg=str(exc) or ResultCode.TYPE_ERROR.label, data=None
    ).model_dump()
    return JSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content=content)


async def validation_exception_handler(request: Request, exc: Union[RequestValidationError, ValidationError]):
    """
    请求验证异常处理器

    Args:
        request: 请求对象
        exc: 验证异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"Validation error: {exc.errors()}",
        exc_info=True,
        extra={"request": request},
    )

    # 构建详细的错误信息
    errors = []
    for error in exc.errors():
        field = ".".join(str(loc) for loc in error["loc"])
        message = error["msg"]
        errors.append(f"{field}: {message}")

    error_msg = "; ".join(errors) if errors else ResultCode.USER_REQUEST_PARAMETER_ERROR.label

    content = Response(code=ResultCode.USER_REQUEST_PARAMETER_ERROR.code, msg=error_msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content=content)


async def user_not_found_handler(request: Request, exc: UserNotFoundException):
    """
    用户未找到异常处理器

    Args:
        request: 请求对象
        exc: 用户未找到异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.warning(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"User not found: {exc.msg}",
        extra={"request": request},
    )
    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content=content)


async def user_account_frozen_handler(request: Request, exc: UserAccountFrozenException):
    """
    用户账户冻结异常处理器

    Args:
        request: 请求对象
        exc: 用户账户冻结异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.warning(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"User account frozen: {exc.msg}",
        extra={"request": request},
    )
    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED, content=content)


async def invalid_token_handler(request: Request, exc: InvalidTokenException):
    """
    无效令牌异常处理器

    Args:
        request: 请求对象
        exc: 无效令牌异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.warning(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"Invalid token: {exc.msg}",
        extra={"request": request},
    )
    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED, content=content)


async def invalid_refresh_token_handler(request: Request, exc: InvalidRefreshTokenException):
    """
    无效刷新令牌异常处理器

    Args:
        request: 请求对象
        exc: 无效刷新令牌异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.warning(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"Invalid refresh token: {exc.msg}",
        extra={"request": request},
    )
    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED, content=content)


async def user_duplicate_handler(request: Request, exc: UserDuplicateException):
    """
    用户重复异常处理器

    Args:
        request: 请求对象
        exc: 用户重复异常

    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)
    logger.warning(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"User duplicate: {exc.msg}",
        extra={"request": request},
    )
    content = Response(code=exc.code, msg=exc.msg, data=None).model_dump()
    return JSONResponse(status_code=status.HTTP_409_CONFLICT, content=content)


async def redis_rrror_handler(request: Request, exc: RedisError):
    """
    Redis异常处理器
    Args:
        request: 请求对象
        exc: Redis异常
    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)  # 获取客户端IP地址
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"RedisError: {exc}",
        exc_info=True,
        extra={"request": request},
    )
    content = Response.failed(msg=str(exc)).model_dump()
    return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=content)


async def unicode_encode_error_handler(request: Request, exc: UnicodeEncodeError):
    """
    UnicodeEncodeError异常处理器
    Args:
        request: 请求对象
        exc: UnicodeEncodeError异常
    Returns:
        JSONResponse: 异常响应
    """
    client_ip = get_client_ip(request)  # 获取客户端IP地址
    logger.error(
        f"[{request.method} {request.url.path}] Client IP: {client_ip} | " f"UnicodeEncodeError: {exc}",
        exc_info=True,
        extra={"request": request},
    )
    content = Response.failed(result_code=ResultCode.UNICODE_ENCODE_ERROR, msg=str(exc)).model_dump()
    return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=content)
